package com.gomoney.oauth2.gateway.common.config;

import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import com.alibaba.fastjson.JSONObject;
import com.gomoney.oauth2.gateway.common.util.JwtTokenUtil;
import com.gomoney.oauth2.gateway.common.util.RedisUtil;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Configuration
public class GatewayConfigurer {

    @Autowired
    private RedisUtil redisUtil;

    public static final String OAUTH_PREFIX = "oauth:jwt:";// pc端前缀

    public static final String OAUTH_PREFIX_REFRESH = "oauth:jwt:refresh:";// pc端刷新token前缀

    @Bean
    public RouteLocator routes(RouteLocatorBuilder builder) {
        return builder.routes().route("gomoney-auth", r -> r.path("/gomoney-auth/oauth/**")
                .filters(f -> f.modifyResponseBody(String.class, String.class, (exchange, s) -> {
                    String path = exchange.getRequest().getURI().getPath();
                    if ("/gomoney-auth/oauth/token".equals(path)) {
                        JSONObject jsonObject = JSONObject.parseObject(s);
                        System.out.println("***************************************");
                        System.out.println("***************************************");
                        System.out.println("***************************************");
                        System.out.println(jsonObject.getString("access_token"));
                        String t = JwtTokenUtil.parseToken(jsonObject.getString("access_token"));
                        System.out.println(t);
                        System.out.println("***************************************");
                        System.out.println("***************************************");
                        System.out.println("***************************************");
                        String username = jsonObject.parseObject(jsonObject.getString("info")).getString("name");
                        String access_token = OAUTH_PREFIX + jsonObject.getString("access_token");
                        if (redisUtil.getAll("*") != null) {
                            Set<Object> keys = redisUtil.getAll("*");
                            for (Object k : keys) {
                                try {
                                    if (redisUtil.get(k.toString()).toString().equals(username)) {
                                        String access = k.toString();
                                        redisUtil.del(access);
                                        String refresh_token = OAUTH_PREFIX_REFRESH + access.replaceAll(OAUTH_PREFIX, "");
                                        redisUtil.del(refresh_token);
                                        break;
                                    }
                                } catch (Exception e) {
                                    continue;
                                }
                            }
                        }
                        Long expires_in = jsonObject.getLong("expires_in") != null ? jsonObject.getLong("expires_in") : 0;
                        String refresh_token = jsonObject.getString("refresh_token");
                        System.out.println(jsonObject);
                        System.out.println("expires_in" + expires_in);
                        redisUtil.set(access_token, username,
                                expires_in);
                        redisUtil.set(OAUTH_PREFIX_REFRESH + access_token.replaceAll(OAUTH_PREFIX, ""), refresh_token, expires_in + 1800);
                    }
                    return Mono.just(s);
                })).uri("lb://gomoney-auth")).build();
    }

/*    @Autowired
    private AuthService authService;

    @Bean
    public AuthGlobalFilter authGlobalFilter() {
        return new AuthGlobalFilter(authService);
    }*/

    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public GatewayConfigurer(ObjectProvider<List<ViewResolver>> viewResolversProvider,
                             ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        // Register the block exception handler for Spring Cloud Gateway.
        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }

    @Bean
    @Order(-1)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }

    @PostConstruct
    public void doInit() {
        initGatewayRules();
    }


    private void initGatewayRules() {
        Set<GatewayFlowRule> rules = new HashSet<>();
        rules.add(new GatewayFlowRule("gomoney-auth")
                .setCount(10) // 限流阈值
                .setIntervalSec(1) // 统计时间窗口，单位是秒，默认是 1 秒
        );
        rules.add(new GatewayFlowRule("gomoney-file")
                .setCount(10) // 限流阈值
                .setIntervalSec(1) // 统计时间窗口，单位是秒，默认是 1 秒
        );
        GatewayRuleManager.loadRules(rules);
    }
}
